package cn.jbolt.common.config;

import com.jfinal.config.Constants;
import com.jfinal.config.Handlers;
import com.jfinal.config.Interceptors;
import com.jfinal.config.JFinalConfig;
import com.jfinal.config.Plugins;
import com.jfinal.config.Routes;
import com.jfinal.core.JFinal;
import com.jfinal.core.paragetter.ParaProcessorBuilder;
import com.jfinal.kit.Prop;
import com.jfinal.kit.PropKit;
import com.jfinal.kit.StrKit;
import com.jfinal.template.Engine;
import com.jfinal.template.source.ClassPathSourceFactory;
import com.xxl.sso.core.util.JedisUtil;
import com.jfinal.ext.handler.ContextPathHandler;
import com.jfinal.ext.interceptor.SessionInViewInterceptor;
import com.jfinal.plugin.druid.DruidPlugin;
import com.jfinal.plugin.redis.RedisPlugin;

import org.beetl.core.GroupTemplate;
import org.beetl.ext.jfinal3.JFinal3BeetlRenderFactory;

import com.alibaba.druid.filter.stat.StatFilter;
import com.alibaba.druid.wall.WallFilter;
import com.alibaba.fastjson.JSONObject;
import com.jfinal.plugin.activerecord.ActiveRecordPlugin;
import com.jfinal.plugin.activerecord.dialect.MysqlDialect;
import com.jfinal.render.ViewType;

import cn.jbolt.common.model._MappingKit;
import cn.jbolt.index.IndexController;
import pers.rcl.common.routes.AutoBindRoutes;
import pers.rcl.interceptor.SysInterceptor;
import pers.rcl.plugin.JSONObjectGetter;
import pers.rcl.plugin.QuartzPlugin;
import pers.rcl.web.TestIdController;

public class MainConfig extends JFinalConfig {
	/**
	 * 将全局配置提出来 方便其他地方重用
	 */
	private static Prop p;
	private WallFilter wallFilter;

	/**
	 * 配置JFinal常量
	 */
	@Override
	public void configConstant(Constants me) {
		// 读取数据库配置文件
		loadConfig();

		// 设置当前是否为开发模式
		me.setDevMode(p.getBoolean("devMode"));
		// 设置默认上传文件保存路径 getFile等使用
		me.setBaseUploadPath("upload/temp/");
		// 设置上传最大限制尺寸
		// me.setMaxPostSize(1024*1024*10);
		// 设置默认下载文件路径 renderFile使用
		me.setBaseDownloadPath("download");
		// 设置默认视图类型
		me.setViewType(ViewType.JFINAL_TEMPLATE);
		// 设置404渲染视图
		// me.setError404View("404.html");

		// 设置启用依赖注入
		me.setInjectDependency(true);

		// 设置主视图为Beetl
		JFinal3BeetlRenderFactory rf = new JFinal3BeetlRenderFactory();
		rf.config();
		me.setRenderFactory(rf);
		

		GroupTemplate gt = rf.groupTemplate;
		// 根据gt可以添加扩展函数，格式化函数，共享变量等
		

		// 使用JSONObject 作为action参数类型
		ParaProcessorBuilder.me.regist(JSONObject.class, JSONObjectGetter.class, null);
		
		//初始化xxl-sso redis
		JedisUtil.init(p.get("xxl.sso.redis.address"));

	}

	/**
	 * 配置项目路由 路由拆分到 FrontRutes 与 AdminRoutes 之中配置的好处： 1：可分别配置不同的 baseViewPath 与
	 * Interceptor 2：避免多人协同开发时，频繁修改此文件带来的版本冲突 3：避免本文件中内容过多，拆分后可读性增强 4：便于分模块管理路由
	 */
	@Override
	public void configRoute(Routes me) {
		// 推荐拆分方式 如果需要就解开注释 创建对应的 Routes
		// me.add(new AdminRoutes());//配置后台管理系统路由

		// me.add(new WechatRoutes());//配置微信端访问路由

		// 普通不拆分的方式配置 如下
		// 设置默认访问首页路由 可使用http://localhost:port 直接访问 如果80端口 port可以省略
		me.add("/", IndexController.class);
		me.add("/test", TestIdController.class);

		// 开启注解配置路由
		AutoBindRoutes autoBindRoutes = new AutoBindRoutes();
		autoBindRoutes.setBaseViewPath("/WEB-INF/views");
		me.add(autoBindRoutes);
	}

	// 先加载开发环境配置，再追加生产环境的少量配置覆盖掉开发环境配置
	static void loadConfig() {

		// 根据配置文件确定开启 不同环境的配置
		p = PropKit.use("config.properties");
		String activeConfig = PropKit.get("profiles.active");
		if (!StrKit.isBlank(activeConfig)) {
			p.appendIfExists(activeConfig + "/config-" + activeConfig + ".properties");
			p.appendIfExists(activeConfig + "/app.properties");
		}
	}

	/**
	 * 获取数据库插件 抽取成独立的方法，便于重用该方法，减少代码冗余;使用配置文件的方式进行多数据源的配置
	 */
	public void getDruidPlugin(Plugins me) {

		String data = p.get("datas");

		String[] datas = data.split(",");

		for (int i = 0; i < datas.length; i++) {
			DruidPlugin dbPlugin = new DruidPlugin(p.get(datas[i] + ".jdbcUrl"), p.get(datas[i] + ".user"), p.get(datas[i] + ".password"));

			wallFilter = new WallFilter(); // 加强数据库安全
			wallFilter.setDbType(p.get(datas[i] + ".dbType"));
			dbPlugin.addFilter(wallFilter);
			dbPlugin.addFilter(new StatFilter()); // 添加 StatFilter 才会有统计数据
			dbPlugin.setDriverClass("com.mysql.jdbc.Driver");

			// 数据映射 配置ActiveRecord插件
			ActiveRecordPlugin arp = new ActiveRecordPlugin(datas[i], dbPlugin);
			
			//注册sql模板
			arp.getEngine().setSourceFactory(new ClassPathSourceFactory());//不可缺少，导致项目启动报错
			arp.addSqlTemplate("/sql/sys_all.sql");
			
			arp.setShowSql(p.getBoolean("devMode"));
			arp.setDialect(new MysqlDialect());
			
			/******** 在此添加数据库 表-Model 映射 *********/
			// 如果使用了JFinal Model 生成器 生成了BaseModel 把下面注释解开即可
			_MappingKit.mapping(arp,datas[i]);

			// 添加到插件列表中
			me.add(dbPlugin);
			me.add(arp);
		}

	}

	/**
	 * 配置JFinal插件 数据库连接池 ActiveRecordPlugin 缓存 定时任务 自定义插件
	 */
	@Override
	public void configPlugin(Plugins me) {
		// 配置数据库连接池插件
		getDruidPlugin(me);
		
		// 配置Quartz
		QuartzPlugin quartz = new QuartzPlugin();
		me.add(quartz);
		
		//配置redis
		RedisPlugin redisPlugin = new RedisPlugin("my_test", "127.0.0.7", 6379, 1440, "123456");
		me.add(redisPlugin);
	}

	/**
	 * 配置全局拦截器
	 */
	@Override
	public void configInterceptor(Interceptors me) {
		me.addGlobalActionInterceptor(new SessionInViewInterceptor());
		// 登录验证
		me.add(new SysInterceptor());
	}

	/**
	 * 配置全局处理器
	 */
	@Override
	public void configHandler(Handlers me) {
		// 说明：druid的统计页面涉及安全性 需要自行处理根据登录权限判断是否能访问统计页面
		// me.add(DruidKit.getDruidStatViewHandler()); // druid 统计页面功能
		System.out.println("ctx:" + new ContextPathHandler("ctx"));
		me.add(new ContextPathHandler("ctx"));
	}

	/**
	 * JFinal启动后调用
	 */
	@Override
	public void afterJFinalStart() {
		// 让 druid 允许在 sql 中使用 union
		// https://github.com/alibaba/druid/wiki/%E9%85%8D%E7%BD%AE-wallfilter
		wallFilter.getConfig().setSelectUnionCheck(false);
	}

	/**
	 * 配置模板引擎
	 */
	@Override
	public void configEngine(Engine me) {
		// 配置模板支持热加载
		me.setDevMode(p.getBoolean("engineDevMode", false));
		// 这里只有选择JFinal TPL的时候才用
		// 配置共享函数模板
		// me.addSharedFunction("/view/common/layout.html")
	}

	public Prop getUtilProp() {
		return p;
	}

}